﻿using System;
using OverStore.Configuration.Validation;
using OverStore.Exceptions.Configuration;
using OverStore.Runtime.OverStoreContext;
using OverStore.Runtime.Storage;
using OverStore.Runtime.ObjectRepository.IdentifierProvider;

namespace OverStore.Configuration.ObjectRepository.IdentifierProvider
{
    /// <summary>
    /// Configuration options for creating instances of <see cref="DelegateIdentifierProvider{TIdentifier}"/> component.
    /// </summary>
    /// <typeparam name="TIdentifier">The type of the identifier.</typeparam>
    public class DelegateIdentifierProviderConfiguration<TIdentifier> : IComponentConfiguration<IIdentifierProvider<TIdentifier>>, ISupportValidation
    {
        /// <summary>
        /// Gets or sets the delegate that extracts identifier from data record.
        /// </summary>
        /// <result>The provide identifier.</result>
        public Func<TypedRecord, TIdentifier> ProvideIdentifier { get; set; }

        /// <summary>
        /// Creates the new instance of <typeparamref name="TComponent"/> type using set of services provided by <paramref name="context"/> object.
        /// </summary>
        /// <param name="context">The context provides access to services shared between components.</param>
        /// <returns>
        /// The new instance of <typeparamref name="TComponent"/> class.
        /// </returns>
        IIdentifierProvider<TIdentifier> IComponentConfiguration<IIdentifierProvider<TIdentifier>>.CreateComponent(IOverStoreContext context)
        {
            if (Object.ReferenceEquals(context, null))
                throw new ArgumentNullException("context");
            if (ProvideIdentifier == null)
                throw this.ConfigurationException("Provide Identifier delegate is missing.");
            return new DelegateIdentifierProvider<TIdentifier>(ProvideIdentifier);
        }

        /// <summary>
        /// Perform component validation. Method should validate only
        /// component configuration itself, not sub components.
        /// If configuration is valid, null result should returns.
        /// </summary>
        /// <returns>
        ///     <see cref="T:OverStore.Configuration.ValidationResults"/> describes errors found in component configuration.
        /// </returns>
        ValidationResult ISupportValidation.Validate()
        {
            return new ValidationResult(this).AddError(ProvideIdentifier == null, "Provide identifier delegate is missing.");
        }
    }
}
